import { AudioClip, AudioSource, Node } from 'cc';
import { Manager } from './Manager';
import { AudioBgm } from './AudioBgm';
import { AudioEffect } from './AudioEffect';
import type { LoadItem } from '../declarations';
import { Numbers } from '../../../../wing/assets/src';
import { app } from '../application';

/**
 * - 作者: DoooReyn
 * - 日期: 2023.10.31
 * - 名称: AudioPlayer
 * - 描述: 音频播放器
 */
export class AudioPlayer extends Manager {
    /** 事件类型 */
    public static readonly EventType = {
        /** BGM 正在播放 */
        BgmPlaying: 'bgm-playing',
        /** BGM 开始播放 */
        BgmStart: 'bgm-started',
        /** BGM 结束播放 */
        BgmEnded: 'bgm-ended',
    };

    /** 音乐组件 */
    private __bgm: AudioBgm;

    /** 音效组件 */
    private __eff: AudioEffect;

    /** 组件容器 */
    private __container: Node | null;

    public get uname(): string {
        return 'AudioPlayer';
    }

    /** 组件容器 */
    public get node() {
        return this.__container;
    }

    /** @param container 组件容器 */
    protected async onInit(container: Node): Promise<void> {
        this.__container = container;
        this.__bgm = this.node!.getComponent(AudioBgm) || this.node!.addComponent(AudioBgm);
        this.__eff = this.node!.getComponent(AudioEffect) || this.node!.addComponent(AudioEffect);
        this.__bgm.volume = this.bgmVolume;
        this.__eff.volume = this.effectVolume;
        this.node!.on(AudioSource.EventType.STARTED, this.onBgmStart, this);
        this.node!.on(AudioSource.EventType.ENDED, this.onBgmComplete, this);
    }

    protected async onDeinit(): Promise<void> {
        this.__container = null;
    }

    /**
     * 背景音乐开始播放回调
     * - 注意：如果设置成循环播放，该回调是不会被调用的
     * @param source 音源
     */
    private onBgmStart(source: AudioSource) {
        if (source === this.__bgm) {
            this.emit(AudioPlayer.EventType.BgmStart, {
                name: this.__bgm.name,
                uuid: this.__bgm.uuid,
                loop: this.__bgm.loop,
                volume: this.__bgm.volume,
                sampleRate: this.__bgm.getSampleRate(),
                duration: this.__bgm.duration,
            });
        }
    }

    /**
     * 背景音乐结束播放回调
     * - 注意：如果设置成循环播放，该回调是不会被调用的
     * @param source 音源
     */
    private onBgmComplete(source: AudioSource) {
        if (source === this.__bgm) {
            this.emit(AudioPlayer.EventType.BgmEnded, {
                name: this.__bgm.name,
                uuid: this.__bgm.uuid,
            });
        }
    }
    /**
     * 播放音乐
     * @param options 选项
     * @param options.loop 默认开启循环
     */
    public playBgm(options: LoadItem<AudioClip> & { loop?: boolean }) {
        options.loop ??= true;
        this.bgmOn && this.__bgm.load(options);
    }

    /**
     * 播放音效
     * @param options 选项
     */
    public playEffect(options: LoadItem<AudioClip>) {
        this.effectOn && this.__eff.load(options);
    }

    /**
     * 背景音乐是否正在播放
     */
    public get isBgmPlaying() {
        return this.__bgm.playing;
    }

    /**
     * 音乐开关
     */
    public get bgmOn() {
        return app.preferences.read('bgmOn');
    }

    /**
     * 设置音乐开关
     */
    public set bgmOn(v: boolean) {
        if (v === false) this.__bgm.stop();
        app.preferences.write('bgmOn', v);
    }

    /**
     * 音效开关
     */
    public get effectOn() {
        return app.preferences.read('effectOn');
    }

    /**
     * 设置音效开关
     */
    public set effectOn(v: boolean) {
        if (v === false) this.__eff.stop();
        app.preferences.write('effectOn', v);
    }

    /**
     * 音乐音量
     */
    public get bgmVolume() {
        return app.preferences.read('bgmVolume');
    }

    /**
     * 设置音乐音量
     */
    public set bgmVolume(v: number) {
        this.__bgm.volume = v = Numbers.clamp(Numbers.toFractionAfter(v, 2), 0, 1);
        app.preferences.write('bgmVolume', this.__bgm.volume);
    }

    /**
     * 音效音量
     */
    public get effectVolume() {
        return app.preferences.read('effectVolume');
    }

    /**
     * 设置音效音量
     */
    public set effectVolume(v: number) {
        this.__eff.volume = v = Numbers.clamp(Numbers.toFractionAfter(v, 2), 0, 1);
        app.preferences.write('effectVolume', this.__eff.volume);
    }

    /**
     * 暂停全部音频
     */
    public pause() {
        this.__bgm.pause();
        this.__eff.pause();
    }

    /**
     * 恢复全部音频
     */
    public resume() {
        this.__bgm.play();
        this.__eff.play();
    }

    /**
     * 停止全部音频
     */
    public stop() {
        this.__bgm.stop();
        this.__eff.stop();
    }

    /**
     * 释放所有音频资源
     */
    public release() {
        this.__bgm.release();
        this.__eff.release();
    }
}
